package client;

import interfaces.CurrentTurn;
import interfaces.GameStarted;
import interfaces.Heartbeat;
import interfaces.Shoot;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.logging.Level;
import java.util.logging.Logger;

import cipher.SimpleStringCipher;

import panels.ConnectionPanel;
import panels.SeaPanel;

public class GameForm extends javax.swing.JFrame implements MouseListener,Runnable{

	 /**
	 *  For update thread
	 */
	
	private boolean threadRunning = false;
	
	
	
	private static final long serialVersionUID = 1L;
	// GAME PHASES
	public boolean FieldSetup;
    public boolean GameOn;
    private boolean HearIsOn;
    // SERVICES
    private Shoot service;
    private GameStarted game;
    private CurrentTurn turn;
    private Heartbeat beat;
    public String host;
    
    // FOR THREAD
    public static Object lock = new Object();
    
    
    // Variables declaration - do not modify                     
    private panels.ConnectionPanel connectionPanel1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JTabbedPane jTabbedPane1;
    private panels.SeaPanel plansza2;
    // End of variables declaration    
    
    //FOR GAME
    private static int ID;
    public int shootCounter;
    boolean shootChanged=false;
    int shootComp;
    
    
    public static int getID() {
		return ID;
	}
	public static void setID(int iD) {
		ID = iD;
	}
	public GameForm() throws RemoteException, NotBoundException, MalformedURLException {
        initComponents();
        FieldSetup=true;
        GameOn=false;
       

       plansza2.addMouseListener(this);
       this.addMouseListener(this);
       
       jLabel1.setVisible(false);
       jLabel2.setVisible(true);
       if(!connectionPanel1.isStarted())
        {
            
            jTabbedPane1.setEnabledAt( jTabbedPane1.getTabCount()-1, false);
            jTabbedPane1.setSelectedComponent(connectionPanel1);
           
            
        }
       
       /*
        * Lookup services
        */
       
      
//		Registry registry = LocateRegistry.getRegistry();
//       service = (Shoot)registry.lookup(interfaces.Shoot.SERVICE_NAME);
//       game = (GameStarted)registry.lookup(interfaces.GameStarted.SERVICE_NAME);
//       turn = (CurrentTurn)registry.lookup(interfaces.CurrentTurn.SERVIC_NAME);

      // Registry registry = LocateRegistry.getRegistry();
       
       
       

    }
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        connectionPanel1 = new panels.ConnectionPanel();
        plansza2 = new panels.SeaPanel();
        jLabel2 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("ShipsRMI");
        setPreferredSize(new java.awt.Dimension(400, 400));

        jLabel1.setText("jLabel1");

        connectionPanel1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                connectionPanel1MouseClicked(evt);
            }
        });
        jTabbedPane1.addTab("Login", connectionPanel1);

        javax.swing.GroupLayout plansza2Layout = new javax.swing.GroupLayout(plansza2);
        plansza2.setLayout(plansza2Layout);
        plansza2Layout.setHorizontalGroup(
            plansza2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 200, Short.MAX_VALUE)
        );
        plansza2Layout.setVerticalGroup(
            plansza2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 184, Short.MAX_VALUE)
        );

        jTabbedPane1.addTab("Game", plansza2);

        jLabel2.setText("jLabel2");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jLabel1))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(24, 24, 24)
                        .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(60, 60, 60)
                        .addComponent(jLabel2)))
                .addContainerGap(459, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(38, 38, 38)
                        .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 227, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(29, 29, 29)
                        .addComponent(jLabel1))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(48, 48, 48)
                        .addComponent(jLabel2)))
                .addContainerGap(289, Short.MAX_VALUE))
        );

        jTabbedPane1.getAccessibleContext().setAccessibleName("Login");

        pack();
    }// </editor-fold>                        

    
    private void connectionPanel1MouseClicked(java.awt.event.MouseEvent evt) {                                              

    }                     

    @Override
    public void mouseClicked(MouseEvent me) {
        
    }

    
    @Override
    public void mousePressed(MouseEvent me) {
    	setID(ConnectionPanel.getID());
    	plansza2.setID(getID());
    	//System.out.println("I am " + getID() + "my field is" + plansza2.getID());
    	setTitle("ShipRMI - Player " + ID);
    	try {
			if(canShoot())
			{
				jLabel2.setVisible(true);
				jLabel2.setText("Your turn");
			}
			else
			{
				jLabel2.setText("Wait!");
			}
		} catch (RemoteException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
//    	try {
//    		synchronized (lock) {
//			System.out.println("Current player : " + turn.getCuttentTurn() );
//			
//    		}
//		} catch (RemoteException e1) {
//			// TODO Auto-generated catch block
//			e1.printStackTrace();
//		}
        if(me.getSource() == plansza2){
        try{
        	
        	int[] x = {0,100,200};
        	int[] y = {0,100,200};
        	int xN=-10,xF=-1,yN=-1,yF=-1;
        	switch(getID())
        	{
        	case 1: xN=x[0];xF= x[1]; yN =y[0] ; yF=y[1]; break;
        	case 2: xN=x[1];xF= x[2]; yN= y[0] ; yF=y[1]; break;
        	case 3: xN=x[1];xF= x[2]; yN= y[1] ; yF=y[2]; break;
        	case 4: xN=x[0];xF= x[1]; yN= y[1] ; yF=y[2]; break;
        	}
            synchronized(lock)
            {;
            	
            	//Ustaw wlasny statek = kolor jest niebieski = 3;
            	if(FieldSetup)
            	{
                if(canShoot())
                {
                	if(me.getX() >= xN && me.getX()<=xF && me.getY() >=yN &&  me.getY()<=yF 
                			&& plansza2.mainTab[me.getX()/SeaPanel.ROW_SIZE][me.getY()/SeaPanel.ROW_SIZE] !=3 ){
                    plansza2.mainTab[me.getX()/SeaPanel.ROW_SIZE][me.getY()/SeaPanel.ROW_SIZE] = 3;
                    System.out.printf("Shoot on %s \n", SeaPanel.mapField(me.getX(),me.getY()));
                  
                   // plansza2.repaint();
                    String codedX,codedY;
                    Integer x1,y1;
                    x1=me.getX()/10;
                    y1=me.getY()/10;
                    if(me.getX()/10 <10)
                    	codedX="0" + x1.toString();
                    else codedX = x1.toString();
                    if(me.getY()/10 <10)
                    	codedY="0" + y1.toString();
                    else codedY = y1.toString();
                    
					try {
						String encrypted = SimpleStringCipher.encrypt(codedX + ";" + codedY);
						service.placeShip(encrypted);
	                    setShootCounter(getShootCounter()+1);
					} catch (Exception e) {
						System.out.println("Exception during encrypting occured!");
					}
                    System.out.println(codedX + ";" + codedY);
                    
                    
                  
                	}
                }
                if(!canShoot())
                {
                    FieldSetup=false;
                    GameOn=true;
                    setShootCounter(0);
                    System.out.println("Wait for others");
                   
                }
                
            	}// field setup
            	
            	if(GameOn)
            	{
            		shootComp=getShootCounter();
            		//plansza2.setCompareTab(service.getMainTab());
            		if(canShoot())
            		{
            			if(me.getX() >= xN && me.getX()<=xF && me.getY() >=yN &&  me.getY()<=yF )
            					//&& plansza2.mainTab[me.getX()/SeaPanel.ROW_SIZE][me.getY()/SeaPanel.ROW_SIZE] !=2 )
            			{
            				System.out.println("Shoot others dumbas!");
            			}
            			else
            				{
            				if(plansza2.mainTab[me.getX()/SeaPanel.ROW_SIZE][me.getY()/SeaPanel.ROW_SIZE] !=0)
	            					System.out.println("This field has been shot already!");
	            			else{
	            				String codedX,codedY,id;
	                            Integer x1,y1;
	                            x1=me.getX()/10;
	                            y1=me.getY()/10;
	                            if(me.getX()/10 <10)
	                            	codedX="0" + x1.toString();
	                            else codedX = x1.toString();
	                            if(me.getY()/10 <10)
	                            	codedY="0" + y1.toString();
	                            else codedY = y1.toString();
	                            if(getID()<10)
	                            	id ="0" + ((Integer)getID()).toString();
	                            else id = ((Integer)getID()).toString();
	                            String toCrypt;
									try {
										toCrypt = SimpleStringCipher.encrypt(id +";" + codedX +";" + codedY);
										int val =getVal(service.getandsetShoot(toCrypt));
			                            plansza2.mainTab[me.getX()/SeaPanel.ROW_SIZE][me.getY()/SeaPanel.ROW_SIZE]=val;
			                            System.out.println("Shoot on :" +  SeaPanel.mapField(me.getX(),me.getY()) + "recieved " + val);
			                            
									} catch (Exception e) {
										System.out.println("Exception during crypting occured!");
										e.printStackTrace();
									}
	            				
	                            
	                            setShootCounter(getShootCounter()+1);
	                            plansza2.setCompareTab(service.getMainTab());
	                            plansza2.repaint();
	                            shootChanged=true;
                             
	            			}
	            		}
	            	}
            		else
            		{
            			
            			//if(shootComp==getShootCounter() && !shootChanged)
            			//	shootChanged=true;
            			if(shootChanged || plansza2.isDead ) 
            			{
            			if(turn.getCuttentTurn(getID())==getID())
            			if(turn.getCuttentTurn(getID())==4)turn.setCurrentTurn(1,getID());else{
    		    			turn.setCurrentTurn(turn.getCuttentTurn(getID()) +1,getID());}
            			shootChanged=false;
            			setShootCounter(0);
            			}
            		}
	            }
	        }
        }
        catch(ArrayIndexOutOfBoundsException e)
        {
            jLabel1.setText("Shoot at field!");
        } catch (RemoteException e) {
			e.printStackTrace();
		}
        
        
        }
        //SET INACIVE IF CONNECTED
         if(connectionPanel1.isStarted() && !GameOn)
        {
        	 synchronized(lock)
        	 {
        	FieldSetup=true;
        	 }
            jTabbedPane1.setEnabledAt( jTabbedPane1.getTabCount()-2, false);
            jTabbedPane1.setSelectedComponent(plansza2);
            setHost(connectionPanel1.getHost());
            if (System.getSecurityManager() == null)
            {
                    System.setSecurityManager
                    (new RMISecurityManager());
            } 
            try {
				service = (Shoot)Naming.lookup("rmi://" + getHost() + "/" + interfaces.Shoot.SERVICE_NAME);
				game = (GameStarted)Naming.lookup("rmi://" + getHost() + "/" + interfaces.GameStarted.SERVICE_NAME);
	            turn = (CurrentTurn)Naming.lookup("rmi://" + getHost() + "/" + interfaces.CurrentTurn.SERVIC_NAME);
	            beat = (Heartbeat)Naming.lookup("rmi://" + getHost() + "/" + interfaces.Heartbeat.SERVICE_NAME );
	            setHearIsOn(true);
	            
	        } catch (MalformedURLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (NotBoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	           /*
	            * ThreadStart
	            */
	       new Thread(this).start();
           
            
        }
    }

    private int getVal(String getandsetShoot) {
		
		int val = Integer.parseInt(getandsetShoot.substring(getandsetShoot.length()-1));
		return val;

	}
	@Override
    public void mouseReleased(MouseEvent me) {
        
    }

    @Override
    public void mouseEntered(MouseEvent me) {
        if(jTabbedPane1.getSelectedComponent() == plansza2)
        {        
        jLabel1.setVisible(true);
        jLabel1.setText("You can shoot now");
        }
        else if (me.getSource() == this)
        {
            jLabel1.setVisible(false);
            this.repaint();
        }
                  
       
    }

    @Override
    public void mouseExited(MouseEvent me) {
        jLabel1.setVisible(false);
        
        
    
    }
	public int getShootCounter() {
		return shootCounter;
	}
	public void setShootCounter(int shootCounter) {
		this.shootCounter = shootCounter;
	}
	public boolean canShoot() throws RemoteException
	{
		int shootCounter = getShootCounter();
		if(plansza2.isDead)
			return false;
			else
			{
	
					if(GameOn)
					{
						if(game.isReady())
						if(turn.getCuttentTurn(getID())==getID() && getShootCounter()<3)
						{
							return true;
						}
						else{
							return false;
						}
						else return false;
					}
					else if(FieldSetup)
					{
						if(shootCounter<4)
						{
							return true;
						}
						else{
							
							return false;
						}
					}
					else return false;
		
			}
	}
	

	public String getHost() {
		return host;
	}
	public void setHost(String host) {
		this.host = host;
	}
	public synchronized void setThreadRunning(boolean threadRunning) {
		this.threadRunning = threadRunning;
	}
	public synchronized boolean isThreadRunning() {
		return threadRunning;
	}
	@Override
	public void run() {
		//System.out.println("WORKING!");
		
		while(connectionPanel1.isServerRunning())
		{
			synchronized (plansza2){
			plansza2.repaint();
			}
			if(isHearIsOn())
			try{
				switch(getID())
				{
				case 1: 
				{
					beat.setBeat1(true);
				}
					break;
				case 2:
				{
					beat.setBeat2(true);
				}
					break;
				case 3:
				{
					beat.setBeat3(true);
				}
					break;
				case 4: 
				{
					beat.setBeat4(true);
				}
					break;
				}
			}
			catch (RemoteException re)
			{}
			catch (Exception e) 
			{
				e.printStackTrace();
			}		
		
		}
	}
	public synchronized void setHearIsOn(boolean hearIsOn) {
		HearIsOn = hearIsOn;
	}
	public synchronized boolean isHearIsOn() {
		return HearIsOn;
	}

				


    

   
    
}
